
//
// 20040115 - AH  - Created.
// 20040423 - AH  - Added createDialog.
// 20040905 - AH  - Missing javadoc.
// 20040907 - AH  - Made chkArg methods public.
// 20041025 - AH  - Added getInvokeAction(Dialog, String).
// 20041105a- AH  - Removed no longer used int constants.
// 20041105b- AH  - Java doc. review.
// 20050208 - AH  - Replaced java 5 deprecated Dialog.show() with
//                  Component.setVisible(true)
// 20050503a- KEM - Added rightTop(Component)
// 20050503b- KEM - Added rightTop(Component c, int topOffset, int rightOffset).
// 20050503c- KEM - Added centerRight(Component c, int rightOffset).
// 20050524 - AH  - Added boolean argument with default value false to 
//                  getDialog message that says close button is to exit
//                  application.
// 20050525 - AH  - Deprecated getDialog with multiple attributes, implemented
//                  DialogData and added getDialog(DialogData).
// 20050603 - AH  - Added Dialogs.DialogData.setContent(Component).
// 20051002a- AH  - Java doc. fixes, problem found by eclipse.
// 20051002b- AH  - Commented away deprecated getDialog methods. 
// 20051006 - KEM - Added centerOnTop().
// 20060623 - AH  - Major format fixes, removed commented code of 20051002b and
//                  generics (move to Java 5).
// 20060913 - AH  - Added width and height properties to DialogData.
// 20070414a- AH  - Added SCREEN_HEIGHT and SCREEN_WIDTH.
// 20070414b- AH  - Added posToRightIfPossible(Component, Dialog) and
//                  posRightToParentIfPossible(Dialog).
//

package org.japril.swing;

import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Toolkit;

/**
 * <p>
 * Usefull utility methods when working with dialogs and frames.
 * </p>
 * 
 * @author Arne Halvorsen (AH) <a href='mailto:arne@bssitt.com'>arne@bssitt.com</a>
 * @author Knut Einar Moldekleiv (KEM) <a href='mailto:knut@bssi.no'>knut@bssi.no</a>
 */
public final class Dialogs
{
  // Utility pattern dictates private constructor.
  private Dialogs(){}

  /**
   * <p>
   *   Display's {@link Dimension}.
   * </p>
   */
  private static final Dimension SCREEN_SIZE=Toolkit.getDefaultToolkit()
    .getScreenSize();
  
  /**
   * <p>
   *   Screen width.
   * </p>
   */
  public static final int SCREEN_WIDTH;
  
  /**
   * <p>
   *   Screen height.
   * </p>
   */
  public static final int SCREEN_HEIGHT;
  
  static
  {
    SCREEN_HEIGHT=SCREEN_SIZE.height;
    SCREEN_WIDTH=SCREEN_SIZE.width;
  }

  /**
   * <p>
   *   Centers {@link Dialog}or {@link Frame}.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void center(Component c)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int x=(SCREEN_SIZE.width - dlgSize.width) / 2;
    int y=(SCREEN_SIZE.height - dlgSize.height) / 2;
    c.setLocation(x, y);
  }

  /**
   * <p>
   *   Centers {@link Dialog}or {@link Frame} on top of parent {@link Dialog}or
   *   {@link Frame}.
   * </p>
   * @param c      <code>Component</code> to place.
   * @param parent <code>Component</code> to place to center on top of.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerOnTop(Component c, Component parent)
  {
    checkArg(c, "parent");
    checkArg(parent);
    Dimension dlgSize=c.getSize();
    Dimension parentSize=c.getSize();
    int x=0;
    if (parent.getWidth()<dlgSize.getWidth())
    {
      x=parent.getLocation().x+(int)(parentSize.getWidth()/2);
    }
    else
    {
      x=(SCREEN_SIZE.width-dlgSize.width)/2;
    }
    int y=0;
    if (parent.getHeight()<dlgSize.getHeight())
    {
      y=parent.getLocation().y+(int)(parentSize.getHeight() / 2);
    }
    else
    {
      y=(SCREEN_SIZE.height-dlgSize.height)/2;
    }
    c.setLocation(x, y);
  }

  /**
   * <p>
   *   Centers 
   *   {@link Frame} or 
   *   {@link Dialog} vertical and align
   *   <code>Component</code>'s left with screen's left.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerLeft(Component c)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int y=(SCREEN_SIZE.height - dlgSize.height) / 2;
    c.setLocation(0, y);
  }

  /**
   * <p>
   *   Centers 
   *   {@link Frame} or 
   *   {@link Dialog} vertical and align
   *   <code>component</code>'s right with screen's right.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerRight(Component c){ centerRight(c, 0); }

  /**
   * <p>
   *   Centers {@link Frame}or {@link Dialog}vertical and align
   *   <code>component</code>'s right with screen's right.
   * </p>
   * @param c           <code>Component</code> to place.
   * @param rightOffset Offset in pixels from right of screen to right of 
   *                    component.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerRight(Component c, int rightOffset)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int x=(SCREEN_SIZE.width - dlgSize.width - rightOffset);
    int y=(SCREEN_SIZE.height - dlgSize.height) / 2;
    c.setLocation(x, y);
  }

  /**
   * <p>
   *   Centers 
   *   {@link Frame} or 
   *   {@link Dialog} horizontal and align
   *   <code>Component</code>'s top with screen's top.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerTop(Component c)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int x=(SCREEN_SIZE.width - dlgSize.width) / 2;
    c.setLocation(x, 0);
  }

  /**
   * <p>
   *   Centers 
   *   {@link Frame} or 
   *   {@link Dialog} horizontal and align
   *   <code>Component</code>'s bottom with screen's bottom.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void centerBottom(Component c)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int x=(SCREEN_SIZE.width - dlgSize.width) / 2;
    int y=(SCREEN_SIZE.height - dlgSize.height);
    c.setLocation(x, y);
  }

  /**
   * <p>
   *   Aligns 
   *   {@link Frame} or 
   *   {@link Dialog} top with screen's top and aligns
   *   <code>component</code>'s right with screen's right.
   * </p>
   * @param c <code>Component</code> to place.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void rightTop(Component c){ rightTop(c, 0, 0); }

  /**
   * <p>
   *   Aligns {@link Frame} or {@link Dialog}top with screen's top and aligns
   *   <code>component</code>'s right with screen's right.
   * </p>
   * @param c           <code>Component</code> to place.
   * @param topOffset   Offset in pixels from top of screen to top of component.
   * @param rightOffset Offset in pixels from right of screen to right of 
   *                    component.
   * @throws IllegalArgumentException If <code>c</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void rightTop(Component c, int topOffset, int rightOffset)
  {
    checkArg(c);
    Dimension dlgSize=c.getSize();
    int x=(SCREEN_SIZE.width - dlgSize.width - rightOffset);
    int y=topOffset;
    c.setLocation(x, y);
  }

  /**
   * <p>
   *   Align given 
   *   {@link Component} right to it's parent 
   *   <code>Component</code>, if has no parent does nothing.
   * </p>
   * @param child <code>Component</code> to align.
   * @throws IllegalArgumentException If <code>child</code> is not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void alignRightToParent(Component child)
  {
    checkArg(child, "child");
    Component parent=child.getParent();
    if (parent != null) alignRightTo(parent, child);
  }

  /**
   * <p>
   *   Align given 
   *   {@link Frame} or 
   *   {@link Dialog} right to given
   *   <code>Frame</code> or <code>Dialog</code>.
   * </p>
   * @param right <code>Component</code> to align <code>left</code> right to.
   * @param left  <code>Component</code> to align right to <code>left</code>.
   * @throws IllegalArgumentException If not both <code>right</code> or 
   *         <code>left</code> is either
   *         <code>Frame</code> or 
   *         <code>Dialog</code> object.
   */
  public static void alignRightTo(Component left, Component right)
  {
    checkArg(left, "left");
    checkArg(right, "right");
    Dimension rd=left.getSize();
    Point rp=left.getLocation();
    int x=rp.x + rd.width;
    int y=rp.y;
    Dimension ld=right.getSize();
    right.setSize(ld.width, rd.height);
    right.setLocation(x, y);
  }

  /**
   * <p>
   *   Align given 
   *   {@link Component} under it's parent component, if has no parent does 
   *   nothing.
   * </p>
   * @param child <code>Component</code> to align.
   * @throws IllegalArgumentException If <code>child</code> is not a 
   *         <code>Frame</code> or <code>Dialog</code> object.
   */
  public static void alignUnderParent(Component child)
  {
    checkArg(child, "child");
    Component parent=child.getParent();
    if (parent != null) alignUnder(parent, child);
  }

  /**
   * <p>
   *   Align given 
   *   {@link Frame} or 
   *   {@link Dialog} under given 
   *   <code>Frame</code> or 
   *   <code>Dialog</code>.
   * </p>
   * @param upper <code>Component</code> to align <code>lower</code> right to.
   * @param lower <code>Component</code> to align under <code>upper</code>.
   * @throws IllegalArgumentException If not both <code>upper</code> or 
   *         <code>lower</code> is either 
   *         <code>Frame</code> or 
   *         <code>Dialog</code> object.
   */
  public static void alignUnder(Component upper, Component lower)
  {
    checkArg(upper, "upper");
    checkArg(lower, "lower");
    Dimension ud=upper.getSize();
    Point up=upper.getLocation();
    int x=up.x;
    int y=up.y + ud.height;
    Dimension ld=lower.getSize();
    lower.setSize(ud.width, ld.height);
    lower.setLocation(x, y);
  }

  /**
   * <p>
   *   Place 
   *   {@link Frame} or 
   *   {@link Dialog} upper left corner at parent's lower right corner.
   * </p>
   * @param child <code>Component</code> to place.
   * @throws IllegalArgumentException If not <code>child</code> is either 
   *         <code>Frame</code> or
   *         <code>Dialog</code> object.
   */
  public static void placeUnderRightParent(Component child)
  {
    checkArg(child, "child");
    Component parent=child.getParent();
    if (parent != null) placeUnderRight(parent, child);
  }

  /**
   * <p>
   *   Place 
   *   {@link Frame} or 
   *   {@link Dialog} upper left corner at given
   *   <code>Frame</code> or 
   *   <code>Dialog</code>'s lower right corner.
   * </p>
   * @param upper <code>Component</code> to place <code>lower</code> relative
   *              to.
   * @param lower <code>Component</code> to place relative to 
   *              <code>upper</code>.
   * @throws IllegalArgumentException If not both <code>upper</code> or 
   *         <code>lower</code> is either 
   *         <code>Frame</code> or 
   *         <code>Dialog</code> object.
   */
  public static void placeUnderRight(Component upper, Component lower)
  {
    checkArg(upper, "upper");
    checkArg(lower, "lower");
    Dimension ud=upper.getSize();
    Point up=upper.getLocation();
    int x=up.x + ud.width;
    int y=up.y + ud.height;
    lower.setLocation(x, y);
  }
  
  /**
   * <p>
   *   Position {@code right} right to {@code left} if possible (if not
   *   position {@code right} at center. 
   * </p>
   * @param left  Left component, if {@code null} position {@code right} at
   *              screen center.
   * @param right Dialog try to put right of {@code left}.
   */
  public static void posToRightIfPossible(Component left, Dialog right)
  {
    if (right==null)
    {
      throw new NullPointerException("right");
    }
    
    if (left==null)
    {
      center(right);
    }
    else
    {
      int maxx=left.getX()+left.getWidth()+right.getWidth();
      if (maxx<=SCREEN_WIDTH) alignRightTo(left, right);
      else                    center(right);
    }
  }
  
  /**
   * <p>
   *   Position {@code c} right to it's parent if possible (if not
   *   position at center). 
   * </p>
   * @param dlg Dialog to position.
   */
  public static void posRightToParentIfPossible(Dialog dlg)
  {
    posToRightIfPossible(dlg.getParent(), dlg);
  }

  /**
   * <p>
   *   Checks that a 
   *   {@link Component} is either a 
   *   {@link Frame} or a
   *   {@link Dialog}.
   * </p>
   * @param c <code>Component</code> to check.
   * @throws NullPointerException If <code>c==null</code>.
   * @throws IllegalArgumentException If <code>c</code> not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code>.
   */
  public static void checkArg(Component c){ checkArg(c, null); }

  /**
   * <p>
   *   Checks that a 
   *   {@link Component} is either a 
   *   {@link Frame} or a
   *   {@link Dialog}.
   * </p>
   * @param c    <code>Component</code> to check.
   * @param name Orginal argument name of <code>c</code> in invoking method, if
   *             <code>null</code> uses 'c'.
   * @throws NullPointerException If <code>c==null</code>.
   * @throws IllegalArgumentException If <code>c</code> not a 
   *         <code>Frame</code> or
   *         <code>Dialog</code>.
   */
  public static void checkArg(Component c, String name)
  {
    name=(name == null) ? "c" : name;
    if (c==null)
    {
      throw new NullPointerException(name);
    }
    if ((c instanceof Dialog) || (c instanceof Frame)) return;
    throw new IllegalArgumentException(name + " nor Frame or Dialog");
  }
  
}
